package cwd.hcn.com.getotgpath;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Parcelable;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.text.TextUtils;
import android.util.Log;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @class name: StorageUtils
 * @class desc: 获取全部存储设备信息封装对象
 * @author: lilongtao
 * @date: 2018/8/10 16:39
 */

public class StorageUtils {
    private static final String TAG = "StorageUtils";

    public static ArrayList<Volume> getVolume(Context context) {
        ArrayList<Volume> storageVolumeList = new ArrayList<>();

        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);

        try {
            Method methodVolumeList = StorageManager.class.getMethod("getVolumeList");

            methodVolumeList.setAccessible(true);

            Object[] volumeList = (Object[]) methodVolumeList.invoke(storageManager);
            if (volumeList != null) {
                Volume volume;
                for (int i = 0; i < volumeList.length; i++) {
                    try {
                        volume = new Volume();
                        volume.setPath((String) volumeList[i].getClass().getMethod("getPath").invoke(volumeList[i]));
                        volume.setRemovable((boolean) volumeList[i].getClass().getMethod("isRemovable").invoke(volumeList[i]));
                        volume.setState((String) volumeList[i].getClass().getMethod("getState").invoke(volumeList[i]));
                        storageVolumeList.add(volume);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    }

                }
            } else {
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }

        return storageVolumeList;
    }

    /**
     * 获取外置SD卡路径
     * @author zgw
     * @time   2018/8/13 0013 16:12:49
     */
    public static String getExStoragePath(Context context, boolean is_removale) {

        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        Class<?> storageVolumeClazz = null;
        try {
            storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
            Method getVolumeList = storageManager.getClass().getMethod("getVolumeList");
            Method getPath = storageVolumeClazz.getMethod("getPath");
            Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
            Object result = getVolumeList.invoke(storageManager);
            final int length = Array.getLength(result);
            for (int i = 0; i < length; i++) {
                Object storageVolumeElement = Array.get(result, i);
                String path = (String) getPath.invoke(storageVolumeElement);
                boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);
                if (is_removale == removable) {
                    return path;
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取所有的外设设备路径:Android 8.0（不包含）以下才可以使用该方法
     * @author zgw
     * @return String[0]-SD卡路径, String[1]-USB路径
     * @time   2018/8/25 0025 11:12:25
     */
    public static String[] getExStoragePath(Context context) {
        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        String path_usb = null;
        String path_sdcard = null;
        String[] exPath = new String[2];
        try {
            //DiskInfo
            Class<?> diskIndoClass = Class.forName("android.os.storage.DiskInfo");
            Method isUsb = diskIndoClass.getMethod("isUsb");
            Method isSd = diskIndoClass.getMethod("isSd");
            //VolumeInfo
            Class<?> volumeClass = Class.forName("android.os.storage.VolumeInfo");
            Method volumeDisk = volumeClass.getMethod("getDisk");
            Method fsUuid = volumeClass.getMethod("getFsUuid");
            Method path = volumeClass.getMethod("getPath");
            Method getVolumes = StorageManager.class.getDeclaredMethod("getVolumes");
            List volumeInfoList = (List) getVolumes.invoke(storageManager);
            for(int i = 0 ; i < volumeInfoList.size(); i++){
                //反射得到diskInfo,并判断是不是usb
                if(volumeDisk.invoke(volumeInfoList.get(i)) != null && (boolean)isUsb.invoke(volumeDisk.invoke(volumeInfoList.get(i)))){
                    path_usb = "mnt/media_rw/" + fsUuid.invoke(volumeInfoList.get(i));
                    Log.e(TAG,"usb path::" + path_usb);
                    exPath[1] = path_usb;
                    Log.e(TAG,"fsUuid::" + fsUuid.invoke(volumeInfoList.get(i)));
                } else if(volumeDisk.invoke(volumeInfoList.get(i)) != null && (boolean)isSd.invoke(volumeDisk.invoke(volumeInfoList.get(i)))){
                    path_sdcard = "" + path.invoke(volumeInfoList.get(i));
                    Log.e(TAG,"sdcard path::" + path_sdcard);
                    exPath[0] = path_sdcard;
                    Log.e(TAG,"fsUuid::" + fsUuid.invoke(volumeInfoList.get(i)));
                } else{
                    Log.e(TAG,"other::" + path.invoke(volumeInfoList.get(i)));
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return exPath;
    }

    /*
     存储设备信息封装类
     */
    public static class Volume {

        protected String path;
        protected boolean removable;
        protected String state;

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public boolean isRemovable() {
            return removable;
        }

        public void setRemovable(boolean removable) {
            this.removable = removable;
        }

        public String getState() {
            return state;
        }

        public void setState(String state) {
            this.state = state;
        }
    }


    public static String[] getDiskInfo(Context context) {
        String[] path = new String[2];
        List<DiskInfo> diskInfoList = new ArrayList<>();
        StorageManager mstorageManager = (StorageManager)context.getApplicationContext().getSystemService(Context.STORAGE_SERVICE);
        try {
            Method methodGetDisks = StorageManager.class.getMethod("getDisks");
            Method methodGetStorageVolumes = StorageManager.class.getMethod("getVolumeList");
            Method getVolumeById = StorageManager.class.getMethod("findVolumeById", String.class);

            StorageVolume[] storageVolumes = (StorageVolume[]) methodGetStorageVolumes.invoke(mstorageManager);
            List disks = (List) methodGetDisks.invoke(mstorageManager);

            //DiskInfo
            Class<?> diskIndoClass = Class.forName("android.os.storage.DiskInfo");
            Method mGetDiskId = diskIndoClass.getMethod("getId");
            Field diskName = diskIndoClass.getField("label");

            //StorageVolume
            Class<?> storageVolumeClass = Class.forName("android.os.storage.StorageVolume");
            Method mGetStorageVolId = storageVolumeClass.getMethod("getId");
            Method mGetStorageVolDescription = storageVolumeClass.getMethod("getDescription", Context.class);
            Method mGetStorageVolPath = storageVolumeClass.getMethod("getPath");
            Method isRemovable = storageVolumeClass.getMethod("isRemovable");
            Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);

            //VolumeInfo
            Class<?> volumeClass = Class.forName("android.os.storage.VolumeInfo");
            Method volumeDiskId = volumeClass.getMethod("getDiskId");

            for(int i = 0; i < disks.size(); i++) {
                DiskInfo diskInfo = new DiskInfo();
                Parcelable parcelable = (Parcelable) disks.get(i);
                diskInfo.diskId = (String) mGetDiskId.invoke(parcelable);
                Log.e(TAG, "diskid : " + diskInfo.diskId);
                String des = (String) diskName.get(parcelable);
                Log.e(TAG, "diskName : " + des);
                diskInfo.name = des;
                diskInfoList.add(diskInfo);
            }

            for(int j = 0; j < storageVolumes.length; j++) {
                DiskPartition partition = new DiskPartition();
                StorageVolume storageVolume = storageVolumes[j];
                partition.partitionId = (String) mGetStorageVolId.invoke(storageVolume);
                if("emulated".equals(partition.partitionId)) { continue; }
                partition.name = (String) mGetStorageVolDescription.invoke(storageVolume, context);
                partition.path = (String) mGetStorageVolPath.invoke(storageVolume);
                Boolean removeAble = ((Boolean) isRemovable.invoke(storageVolume)).booleanValue();
                String state = (String) getVolumeState.invoke(mstorageManager, partition.path);
                if("mounted".equals(state) && removeAble) {
                    partition.diskId = (String) volumeDiskId.invoke(getVolumeById.invoke(mstorageManager, partition.partitionId));
                    for(DiskInfo diskInfo : diskInfoList) {
                        if(diskInfo.diskId.equals(partition.diskId)) {
                            getStorageBlockInfo(partition);
                            diskInfo.diskPartitions.add(partition);
                            Log.e(TAG, "partition.name : " + partition.name);
                            Log.e(TAG, "partition.diskId : " + partition.diskId);
                            Log.e(TAG, "partition.path : " + partition.path);
                            String partitionId = partition.diskId;
                            String[] idSplit = partitionId.split(":");
                            if (idSplit != null && idSplit.length == 2) {
                                if (idSplit[1].startsWith("8,")) {
                                    String usbPath =  partition.path;
                                    path[0] = usbPath;
                                }else{
                                    String sdcardPath =  partition.path;
                                    path[1] = sdcardPath;
                                }
                            }
                        }
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return path;
    }

    private static class DiskInfo {
        public String diskId;
        public String name;
        //public ArrayList diskPartitions = new ArrayList<>();
        public ArrayList<DiskPartition> diskPartitions = new ArrayList<DiskPartition>();
    }

    private static class DiskPartition{
        public String name;
        public String partitionId;
        public String diskId;
        public long totalSize;
        public long avlableSize;
        public String path;
    }

    private static void getStorageBlockInfo(DiskPartition info) {
        if(TextUtils.isEmpty(info.path))
            return;
        android.os.StatFs statfs = new android.os.StatFs(info.path);
        long nBlocSize = statfs.getBlockSizeLong();
        long blockCountLong = statfs.getBlockCountLong();
        long nAvailaBlock = statfs.getAvailableBlocksLong();
        info.totalSize = blockCountLong * nBlocSize;
        info.avlableSize = nBlocSize * nAvailaBlock;
    }

    @TargetApi(Build.VERSION_CODES.N)
    public static List<StorageVolume> getStoragePath(Context context) {
        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        List<StorageVolume> storageVolumes = storageManager.getStorageVolumes();
        return storageVolumes;
    }

}